﻿// 文件使用MiniExcel源码， 使用时需遵循其 Apache License 2.0
// 修改摘要通知： 删除异步、Task等net2.0中不支持的内容，替换原先C#自带的zip处理方式，改用yacomp 进行解压缩。
using ExcelConfig.Excel.Utils;
using System;
using System.Globalization;
using System.Text;

namespace ExcelConfig.Utils
{
    internal static class ReferenceHelper
    {
        internal static string GetCellNumber(string cell)
        {
            var outt = new StringBuilder();
            for(int i = 0; i <cell.Length; i++)if (char.IsDigit(cell[i])) outt.Append(cell[i]);
            return outt.ToString();
        }

        internal static string GetCellLetter(string cell)
        {
            var outt = new StringBuilder();
            for (int i = 0; i < cell.Length; i++) if (char.IsLetter(cell[i])) outt.Append(cell[i]);
            return outt.ToString();
        }

        /// <summary>X=CellLetter,Y=CellNumber,ex:A1=(1,1),B2=(2,2)</summary>
        internal static Tuple2Int ConvertCellToXY(string cell)
        {
            const string keys = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            const int mode = 26;

            //AA=27,ZZ=702
            var cellLetter = GetCellLetter(cell);
            var x = 0;
            for (var i = 0; i < cellLetter.Length; i++) x = x * mode + keys.IndexOf(cellLetter[i]);

            var cellNumber = GetCellNumber(cell);
            return Tuple2Int.Create(x, int.Parse(cellNumber));
        }

        /// <summary>X=CellLetter,Y=CellNumber,ex:A1=(1,1),B2=(2,2)</summary>
        internal static string ConvertXyToCell(int x, int y)
        {
            int dividend = x;
            string columnName = string.Empty;

            while (dividend > 0)
            {
                var modulo = (dividend - 1) % 26;
                columnName = Convert.ToChar(65 + modulo) + columnName;
                dividend = (dividend - modulo) / 26;
            }
            return $"{columnName}{y}";
        }

        /**The code below was copied and modified from ExcelDataReader - @MIT License**/
        /// <summary>
        /// Logic for the Excel dimensions. Ex: A15
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="column">The column, 1-based.</param>
        /// <param name="row">The row, 1-based.</param>
        internal static bool ParseReference(string value, out int column, out int row)
        {
            row = 0;
            column = 0;
            var position = 0;
            const int offset = 'A' - 1;

            if (string.IsNullOrEmpty(value.Trim()))
                return false;

            while (position < value.Length)
            {
                var c = char.ToUpperInvariant(value[position]);
                if (c >= 'A' && c <= 'Z')
                {
                    position++;
                    column *= 26;
                    column += c - offset;
                    continue;
                }

                if (!char.IsLetter(c))
                {
                    if (char.IsDigit(c))
                        break;
                    return false;
                }

                row = 0;
                column = 0;
                position = 0;
                break;
            }

            if (position == 0)
                return false;

            return int.TryParse(value.Substring(position), NumberStyles.None, CultureInfo.InvariantCulture, out row);
        }
    }
}
